package com.nuoniu.sibanyun.service.finance.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.entity.dto.AccountingAuxiliaryLedgerDto;
import com.nuoniu.sibanyun.entity.erp.ErpAccount;
import com.nuoniu.sibanyun.entity.erp.ErpAccounting;
import com.nuoniu.sibanyun.entity.finance.VAccountingAuxiliaryLedger;
import com.nuoniu.sibanyun.entity.finance.VAccountingLedger;
import com.nuoniu.sibanyun.entity.finance.VAccountingSearchProgramme;
import com.nuoniu.sibanyun.entity.finance.VAccountingVoucherDetail;
import com.nuoniu.sibanyun.mapper.finance.VAccountingAuxiliaryLedgerMapper;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpAccountingService;
import com.nuoniu.sibanyun.service.finance.IVAccountingAuxiliaryLedgerService;
import com.nuoniu.sibanyun.service.finance.IVAccountingLedgerService;
import com.nuoniu.sibanyun.service.finance.IVAccountingVoucherDetailService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 辅助总账表 服务实现类
 * </p>
 *
 * @author 小啊刚
 * @since 2021-04-25
 */
@Service
public class VAccountingAuxiliaryLedgerServiceImpl extends ServiceImpl<VAccountingAuxiliaryLedgerMapper, VAccountingAuxiliaryLedger> implements IVAccountingAuxiliaryLedgerService {

    @Autowired
    private IErpAccountService accountService;
    @Autowired
    @Lazy
    private IVAccountingLedgerService ledgerService;
    @Autowired
    private IVAccountingVoucherDetailService voucherDetailService;
    @Autowired
    private IErpAccountingService accountingService;

    @Override
    public Map<String, Object> saveLedger(List<VAccountingAuxiliaryLedger> auxiliaryLedgers) {
        UserInfo userInfo = UserThreadLocal.get();
        ErpAccount account = accountService.getLastErpAccount();
        Map<String, Object> resultMap = new HashMap<>();
        List<String> resultData = new ArrayList<>();
        List<VAccountingAuxiliaryLedger> ledgerList = new ArrayList<>();

        Integer aCount = baseMapper.checkAccountings(userInfo.getCompanyId(), account.getAccountYear());
        if (aCount > 0) {
            resultData.add("已记账,不能设置期初余额");
        }

        List<Long> detailIds = new ArrayList<>();
        for (VAccountingAuxiliaryLedger ledger : auxiliaryLedgers) {
            if (ledger.getId() == null) {
                ledger.setAccountId(account.getId().intValue());
                ledger.setAccountYear(account.getAccountYear());
                ledger.setAccountPeriod(account.getEnableDuration());
                ledger.setCompanyId(userInfo.getCompanyId());
            } else {
                detailIds.add(ledger.getId());
            }
            ledgerList.add(ledger);
        }

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("company_id", userInfo.getCompanyId());
        wrapper.eq("accounting_id", auxiliaryLedgers.get(0).getAccountingId());
        if (detailIds.size() > 0) {
            wrapper.notIn("id", detailIds);
        }
        this.remove(wrapper);

        if (ledgerList.size() > 0) {
            saveOrUpdateBatch(ledgerList);
        }

        resultMap.put("result", resultData);
        resultMap.put("sCount", ledgerList.size());
        resultMap.put("fCount", resultData.size());
        return resultMap;
    }

    @Override
    public void bookAccounting(VAccountingVoucherDetail voucherDetail, ErpAccounting accounting, Integer accountPeriod) {
        VAccountingAuxiliaryLedger auxiliaryLedger = baseMapper.getAuxiliaryLedger(voucherDetail);
        if (auxiliaryLedger == null) {
            auxiliaryLedger = new VAccountingAuxiliaryLedger();
            BeanUtils.copyProperties(voucherDetail, auxiliaryLedger);
            auxiliaryLedger.setCreditAmount(voucherDetail.getCreditAmount());
            auxiliaryLedger.setDebitAmount(voucherDetail.getDebitAmount());
//            if (auxiliaryLedger.getUserId() != null && auxiliaryLedger.getOfficeId() == null) {
////                SysEmployee employee = employeeService.getByUserId(auxiliaryLedger.getUserId().longValue());
////                if (employee != null && employee.getOfficeId() != null) {
////                    auxiliaryLedger.setOfficeId(employee.getOfficeId().intValue());
////                    auxiliaryLedger.setOfficeName(employee.getOfficeName());
////                } else {
////                    auxiliaryLedger.setOfficeId(employee.getCompanyId().intValue());
////                    auxiliaryLedger.setOfficeName(employee.getCompanyName());
////                }
////            }
        } else {
            auxiliaryLedger.setCreditAmount(auxiliaryLedger.getCreditAmount().add(voucherDetail.getCreditAmount()));
            auxiliaryLedger.setDebitAmount(auxiliaryLedger.getDebitAmount().add(voucherDetail.getDebitAmount()));
        }

        //获取上一个期间
        VAccountingVoucherDetail detail = new VAccountingVoucherDetail();
        BeanUtils.copyProperties(voucherDetail, detail);
        detail.setAccountPeriod(voucherDetail.getAccountPeriod().equals(accountPeriod) ? accountPeriod + 1 : accountPeriod);
        VAccountingAuxiliaryLedger upLedger = baseMapper.getUpAuxiliaryLedger(detail);
        if (upLedger != null) {
            if(voucherDetail.getAccountPeriod().equals(accountPeriod)) {
                auxiliaryLedger.setBeginAmount(upLedger.getBeginAmount());
                auxiliaryLedger.setBeginAmountDirection(upLedger.getBeginAmountDirection());
            } else {
                auxiliaryLedger.setBeginAmount(upLedger.getEndAmount());
                auxiliaryLedger.setBeginAmountDirection(upLedger.getEndAmountDirection());
            }
        } else {
            auxiliaryLedger.setBeginAmount(new BigDecimal(0.0));
            auxiliaryLedger.setBeginAmountDirection(3);
        }

        //计算期末
        countEnd(auxiliaryLedger);

        //保存
        saveOrUpdate(auxiliaryLedger);

        /** 依次计算后面期间科目辅助总账*/
        countNextAccounting(auxiliaryLedger, accounting, voucherDetail);
    }

    /**
     * 计算期末
     * @author 小啊刚
     * @date 2021-05-10
     */
    public void countEnd(VAccountingAuxiliaryLedger auxiliaryLedger) {
        ErpAccounting accounting = accountingService.getById(auxiliaryLedger.getAccountingId());
        if(accounting.getDcDirection().equals(1)) {
            //设置期末方向
            auxiliaryLedger.setEndAmountDirection(1);
            if (auxiliaryLedger.getBeginAmountDirection().equals(1)) {
                auxiliaryLedger.setEndAmount(auxiliaryLedger.getBeginAmount().add(auxiliaryLedger.getDebitAmount()).subtract(auxiliaryLedger.getCreditAmount()));
            } else {
                auxiliaryLedger.setEndAmount((auxiliaryLedger.getBeginAmount().multiply(new BigDecimal(-1))).add(auxiliaryLedger.getDebitAmount()).subtract(auxiliaryLedger.getCreditAmount()));
            }
        } else {
            //设置期末方向
            auxiliaryLedger.setEndAmountDirection(2);
            if (auxiliaryLedger.getBeginAmountDirection().equals(2)) {
                auxiliaryLedger.setEndAmount(auxiliaryLedger.getBeginAmount().add(auxiliaryLedger.getCreditAmount()).subtract(auxiliaryLedger.getDebitAmount()));
            } else {
                auxiliaryLedger.setEndAmount((auxiliaryLedger.getBeginAmount().multiply(new BigDecimal(-1))).add(auxiliaryLedger.getCreditAmount()).subtract(auxiliaryLedger.getDebitAmount()));
            }
        }
    }

    /**
     * 计算后面期间科目辅助总账
     *
     * @author 小啊刚
     * @date 2021-04-30
     */
    public void countNextAccounting(VAccountingAuxiliaryLedger accountingLedger, ErpAccounting accounting, VAccountingVoucherDetail voucherDetail) {
        List<VAccountingAuxiliaryLedger> accountingLedgers = new ArrayList<>();
        Map<Integer, VAccountingAuxiliaryLedger> ledgerMap = new HashMap<>();
        ledgerMap.put(accountingLedger.getAccountPeriod(), accountingLedger);
        for (int i = accountingLedger.getAccountPeriod() + 1; i <= 12; i++) {
            voucherDetail.setAccountPeriod(voucherDetail.getAccountPeriod() + 1);
            VAccountingAuxiliaryLedger ledger = baseMapper.getAuxiliaryLedger(voucherDetail);
            if (ledger == null) {
                ledger = new VAccountingAuxiliaryLedger();
                BeanUtils.copyProperties(accountingLedger, ledger);
                ledger.setId(null);
                ledger.setDebitAmount(new BigDecimal(0.0));
                ledger.setCreditAmount(new BigDecimal(0.0));
                ledger.setAccountPeriod(i);
                ledger.setBeginAmount(accountingLedger.getEndAmount());
                ledger.setBeginAmountDirection(accountingLedger.getEndAmountDirection());
            } else {
                ledger.setBeginAmount(ledgerMap.get(i - 1).getEndAmount());
                ledger.setBeginAmountDirection(ledgerMap.get(i - 1).getEndAmountDirection());
                countEnd(ledger);
            }

            ledgerMap.put(i, ledger);
            accountingLedgers.add(ledger);
        }

        saveOrUpdateBatch(accountingLedgers);
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageCrmAccountingAuxiliaryLedger(Page page, VAccountingSearchProgramme searchProgramme) {
        ErpAccount account = accountService.getLastErpAccount();
        UserInfo userInfo = UserThreadLocal.get();
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        searchProgramme.setAccountYear(account.getAccountYear());
        Page<VAccountingAuxiliaryLedger> ledgerPage = baseMapper.pageCrmAccountingAuxiliaryLedger(page, searchProgramme);
        countLedger(ledgerPage);
        return ledgerPage;
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageVendorAccountingAuxiliaryLedger(Page page, VAccountingSearchProgramme searchProgramme) {
        UserInfo userInfo = UserThreadLocal.get();
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        Page<VAccountingAuxiliaryLedger> ledgerPage = baseMapper.pageVendorAccountingAuxiliaryLedger(page, searchProgramme);
        countLedger(ledgerPage);
        return ledgerPage;
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageUserAccountingAuxiliaryLedger(Page page, VAccountingSearchProgramme searchProgramme) {
        UserInfo userInfo = UserThreadLocal.get();
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        Page<VAccountingAuxiliaryLedger> ledgerPage = baseMapper.pageUserAccountingAuxiliaryLedger(page, searchProgramme);
        countLedger(ledgerPage);
        return ledgerPage;
    }

    public void countLedger(Page<VAccountingAuxiliaryLedger> ledgerPage) {
        List<VAccountingAuxiliaryLedger> ledgerList = ledgerPage.getRecords();
        for (VAccountingAuxiliaryLedger ledger : ledgerList) {
            if (ledger.getBeginAmount() != null && ledger.getBeginAmountDirection() != null) {
                if (ledger.getEndAmount().compareTo(BigDecimal.ZERO) == 0) {
                    ledger.setEndAmountDirection(3);
                } else if (ledger.getEndAmount().compareTo(BigDecimal.ZERO) == 1) {
                    ledger.setEndAmountDirection(2);
                } else {
                    ledger.setEndAmountDirection(1);
                }
            }
            countEnd(ledger);
        }

        ledgerPage.setRecords(ledgerList);
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageAuxiliaryBeginList(Page page, VAccountingSearchProgramme searchProgramme) {
        ErpAccount account = accountService.getLastErpAccount();
        searchProgramme.setAccountYear(account.getAccountYear());
        searchProgramme.setCompanyId(UserThreadLocal.get().getCompanyId());
        searchProgramme.setAccountPeriod(account.getEnableDuration());
        return baseMapper.pageAuxiliaryBeginList(page, searchProgramme);
    }

    @Override
    public Integer getAccountingBegin(Integer accountingId) {
        ErpAccount account = accountService.getLastErpAccount();
        return baseMapper.getAccountingBegin(account.getAccountYear(), accountingId);
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageAccountingAuxiliaryLedgerList(Page page, VAccountingSearchProgramme searchProgramme) {
        ErpAccount account = accountService.getLastErpAccount();
        searchProgramme.setAccountYear(account.getAccountYear());
        searchProgramme.setCompanyId(UserThreadLocal.get().getCompanyId());
        searchProgramme.setBeginDate(searchProgramme.getBeginDate().split("-")[1]);
        searchProgramme.setEndDate(searchProgramme.getEndDate().split("-")[1]);
        return baseMapper.pageAccountingAuxiliaryLedgerList(page, searchProgramme);
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageProjectAccountingAuxiliaryLedger(Page page, VAccountingSearchProgramme searchProgramme) {
        UserInfo userInfo = UserThreadLocal.get();
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        Page<VAccountingAuxiliaryLedger> ledgerPage = baseMapper.pageProjectAccountingAuxiliaryLedger(page, searchProgramme);
        countLedger(ledgerPage);
        return ledgerPage;
    }

    @Override
    public Page<VAccountingAuxiliaryLedger> pageOfficeAccountingAuxiliaryLedger(Page page, VAccountingSearchProgramme searchProgramme) {
        UserInfo userInfo = UserThreadLocal.get();
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        Page<VAccountingAuxiliaryLedger> ledgerPage = baseMapper.pageOfficeAccountingAuxiliaryLedger(page, searchProgramme);
        countLedger(ledgerPage);
        return ledgerPage;
    }

    @Override
    public List<AccountingAuxiliaryLedgerDto> pageAccountingAuxiliaryDetailList(VAccountingSearchProgramme searchProgramme, Boolean isShowDetail, Boolean isDayBook) {
        UserInfo userInfo = UserThreadLocal.get();
        List<AccountingAuxiliaryLedgerDto> ledgerDtoList = new ArrayList<>(); //数据组装
        Map<Long, VAccountingAuxiliaryLedger> dtoMap = new HashMap<>(); //年度累计
        VAccountingAuxiliaryLedger upLedger = null; //上个期间数据
        ErpAccount account = accountService.getLastErpAccount();
        searchProgramme.setAccountYear(account.getAccountYear());
        searchProgramme.setCompanyId(userInfo.getCompanyId());
        searchProgramme.setBeginDate(searchProgramme.getBeginDate().split("-")[1]);
        searchProgramme.setEndDate(searchProgramme.getEndDate().split("-")[1]);
        Integer period = ledgerService.getAccountPeriod(account.getAccountYear(), userInfo.getCompanyId());
        ErpAccounting accounting = accountingService.getById(searchProgramme.getAccountingId());

        //获取辅助期初余额
        List<VAccountingAuxiliaryLedger> ledgerList = baseMapper.accountingAuxiliaryDetailList(searchProgramme);
        for (VAccountingAuxiliaryLedger ledger : ledgerList) {
            if (upLedger == null || !upLedger.getBusinessId().equals(ledger.getBusinessId())) { //设置期初
                AccountingAuxiliaryLedgerDto dto = new AccountingAuxiliaryLedgerDto();
                BeanUtils.copyProperties(ledger, dto);
                if (ledger.getAccountPeriod().equals(period) && ledger.getAccountPeriod() > 1) {
                    dto.setPeriodDate(ledger.getAccountYear() + "年1-" + period + "月");
                } else {
                    dto.setPeriodDate(ledger.getPeriodDate());
                }

                dto.setCreditAmount(null);
                dto.setDebitAmount(null);
                dto.setEndAmountDirection(ledger.getBeginAmountDirection());
                dto.setEndAmount(ledger.getBeginAmount());
//                dto.setTitle("期初余额");
                dto.setDescription("期初余额");
                ledgerDtoList.add(dto);
            }

            if (isShowDetail != null && isShowDetail) { //获取总账明细
                searchProgramme.setAccountPeriod(ledger.getAccountPeriod());
                searchProgramme.setBusinessId(ledger.getBusinessId().intValue());
                List<AccountingAuxiliaryLedgerDto> ledgerDetailList = voucherDetailService.getAuxiliaryLedgerDetailList(searchProgramme); //获取凭证明细列表
                BigDecimal dayCreditAmount = new BigDecimal(0.0);
                BigDecimal dayDebitAmount = new BigDecimal(0.0);
                VAccountingLedger dLedger = new VAccountingLedger();
                dLedger.setEndAmount(ledger.getBeginAmount());
                dLedger.setBeginAmount(ledger.getBeginAmount());
                dLedger.setBeginAmountDirection(ledger.getBeginAmountDirection());
                if(accounting.getDcDirection().equals(1)) {
                    if(ledger.getBeginAmountDirection().equals(2)) {
                        dLedger.setBeginAmount(ledger.getBeginAmount().multiply(new BigDecimal(-1)));
                    }
                } else {
                    if(ledger.getBeginAmountDirection().equals(1)) {
                        dLedger.setBeginAmount(ledger.getBeginAmount().multiply(new BigDecimal(-1)));
                    }
                }

                for (Integer i = 0; i < ledgerDetailList.size(); i++) {
                    //设置明细账期末余额
                    AccountingAuxiliaryLedgerDto ledgerDto = ledgerDetailList.get(i);
                    BigDecimal creditAmount = ledgerDto.getCreditAmount() != null ? ledgerDto.getCreditAmount() : new BigDecimal(0.0);
                    BigDecimal debitAmount = ledgerDto.getDebitAmount() != null ? ledgerDto.getDebitAmount() : new BigDecimal(0.0);
                    if(accounting.getDcDirection().equals(1)) {
                        ledgerDto.setEndAmountDirection(1);
                        dLedger.setEndAmount(dLedger.getEndAmount().add(debitAmount).subtract(creditAmount));
                        ledgerDto.setEndAmount(dLedger.getEndAmount());
                    } else {
                        ledgerDto.setEndAmountDirection(2);
                        dLedger.setEndAmount(dLedger.getEndAmount().add(creditAmount).subtract(debitAmount));
                        ledgerDto.setEndAmount(dLedger.getEndAmount());
                    }
                    ledgerDto.setAccountingName(ledger.getAccountingName());
                    ledgerDto.setAccountingCode(ledger.getAccountingCode());
                    ledgerDtoList.add(ledgerDto);

                    if (isDayBook) { //日记账
                        if (ledgerDto.getCreditAmount() != null) {
                            dayCreditAmount = dayCreditAmount.add(ledgerDto.getCreditAmount());
                        } else {
                            dayDebitAmount = dayDebitAmount.add(ledgerDto.getDebitAmount());
                        }

                        if (ledgerDetailList.size() == 1 || ledgerDetailList.size() == i + 1 || (!ledgerDto.getPeriodDate().equals(ledgerDetailList.get(i + 1).getPeriodDate()))) {
                            AccountingAuxiliaryLedgerDto dayLedger = new AccountingAuxiliaryLedgerDto();
                            BeanUtils.copyProperties(ledgerDto, dayLedger);
                            dayLedger.setDebitAmount(dayDebitAmount);
                            dayLedger.setCreditAmount(dayCreditAmount);
                            dayLedger.setDescription("本日合计");
//                            dayLedger.setTitle("本日合计");
                            dayLedger.setCode("");
                            dayLedger.setAccountingName(ledger.getAccountingName());
                            dayLedger.setAccountingCode(ledger.getAccountingCode());
                            dayLedger.setEndAmount(ledgerDto.getEndAmount());
                            dayCreditAmount = new BigDecimal(0.0);
                            dayDebitAmount = new BigDecimal(0.0);
                            ledgerDtoList.add(dayLedger);
                        }
                    }
                }
            }

            if (searchProgramme.getIsNoBookkeeping() != null && searchProgramme.getIsNoBookkeeping().equals(1)) { //计算未记账
                ledger.setCreditAmount(ledger.getCreditAmount().add(ledger.getNoCreditAmount()));
                ledger.setDebitAmount(ledger.getDebitAmount().add(ledger.getNoDebitAmount()));
                countEnd(ledger);
            }

            AccountingAuxiliaryLedgerDto mDto = new AccountingAuxiliaryLedgerDto();
            BeanUtils.copyProperties(ledger, mDto);
            if (ledger.getAccountPeriod().equals(period) && ledger.getAccountPeriod() > 1) {
                mDto.setPeriodDate(ledger.getAccountYear() + "年1-" + period + "月");
            } else {
                mDto.setPeriodDate(ledger.getPeriodDate());
            }

            mDto.setDescription("本月合计");
//            mDto.setTitle("本月合计");
            ledgerDtoList.add(mDto);

            if (dtoMap == null || dtoMap.get(ledger.getBusinessId()) == null) {
                dtoMap.put(ledger.getBusinessId(), ledger);
            } else {
                VAccountingAuxiliaryLedger accountingLedger = dtoMap.get(ledger.getBusinessId());
                accountingLedger.setDebitAmount(accountingLedger.getDebitAmount().add(ledger.getDebitAmount()));
                accountingLedger.setCreditAmount(accountingLedger.getCreditAmount().add(ledger.getCreditAmount()));
                accountingLedger.setEndAmountDirection(ledger.getEndAmountDirection());
                dtoMap.put(ledger.getBusinessId(), accountingLedger);
            }

            AccountingAuxiliaryLedgerDto yDto = new AccountingAuxiliaryLedgerDto();
            BeanUtils.copyProperties(ledger, yDto);
            if (ledger.getAccountPeriod().equals(period) && ledger.getAccountPeriod() > 1) {
                yDto.setPeriodDate(ledger.getAccountYear() + "年1-" + period + "月");
            } else {
                yDto.setPeriodDate(ledger.getPeriodDate());
            }

            BigDecimal creditAmount = dtoMap.get(ledger.getBusinessId()).getCreditAmount();
            BigDecimal debitAmount = dtoMap.get(ledger.getBusinessId()).getDebitAmount();
            yDto.setCreditAmount(creditAmount);
            yDto.setDebitAmount(debitAmount);
            yDto.setDescription("本年累计");
//            yDto.setTitle("本年累计");
            ledgerDtoList.add(yDto);
            upLedger = ledger;
        }
        
        return ledgerDtoList;
    }
}
